package com.frontop.system.modules.project.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.frontop.common.annotation.AnonymousAccess;
import com.frontop.common.domain.UserJurisdiction;
import com.frontop.common.util.JwtUtil;
import com.frontop.common.util.ResultJsonUtil;
import com.frontop.system.config.MultipartFileToFile;
import com.frontop.system.config.MultipartFlieUtil;
import com.frontop.system.config.NacosConfig;
import com.frontop.system.modules.project.model.Chunk;
import com.frontop.system.modules.project.model.SysProject;
import com.frontop.system.modules.project.service.SysProjectService;
import com.frontop.system.modules.project.vo.SysProjectVO;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * 项目表 前端控制器
 * </p>
 *
 * @author YangJia
 * @since 2021-12-21
 */
@RestController
@RequestMapping("/sys-project")

@Slf4j
public class SysProjectController {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    SysProjectService sysProjectService;
    @Autowired
    NacosConfig nacosConfig;
    @Autowired
    MultipartFileToFile multipartFileToFile;

    @Value("${redisKeyConfig.userFollowPro}")
    private String userFollowPro;
    @Value("${redisKeyConfig.proFollow}")
    private String proFollow;

    @ApiOperation(value = "项目列表")
    @PostMapping("/projectList")
    public ResultJsonUtil<Object> projectList(@RequestBody(required = false) SysProjectVO vo, HttpServletRequest request,
                                              Authentication authentication) {
        Page<SysProject> page = new Page<>(vo.getPageNo(), vo.getPageSize());
        //获取当前登录用户基本权限信息
        UserJurisdiction userJurisdiction = JwtUtil.getUserJurisdiction(authentication);
        if(vo.getIsFollow() != null && vo.getIsFollow().equals(1)){
            //获取关注列表
            Set zSet =  redisTemplate.opsForZSet().range(userFollowPro+userJurisdiction.getUserId(),0,-1);
            vo.setUserFollowPro(zSet);
        }

        page = sysProjectService.selectProjectPage(page, vo);
        page.getRecords().stream().forEach(v->{
            //查询此项目关注量
            v.setGzCount(redisTemplate.opsForSet().size(proFollow+v.getId()));
            //判断用户是否关注了此项目作品
            if(redisTemplate.opsForZSet().rank(userFollowPro+userJurisdiction.getUserId(),v.getId()) != null){
                v.setIsBgz(1);
            }
            v.setGzCount(redisTemplate.opsForSet().size(proFollow+v.getId()));
        });

        return new ResultJsonUtil().success(page);
    }

    @ApiOperation(value = "上传封面")
    @PostMapping("/uploadProjectImage")
    public ResultJsonUtil<Object> uploadProjectImage(@RequestParam("file") MultipartFile multipartFile,
                                                     @RequestParam("id") Integer id,
                                                      Authentication authentication,
                                                      HttpServletRequest request) {
        String imageName =  MultipartFlieUtil.upFile(multipartFile,nacosConfig.getUploadPath()+"project");
        SysProject sysProject = new SysProject();
        sysProject.setId(id);
        sysProject.setImage(imageName);
        sysProjectService.updateById(sysProject);
        return new ResultJsonUtil().success("上传成功");
    }

    @ApiOperation(value = "新增项目")
    @PostMapping("/addOrUpProject")
    @Transactional
    public ResultJsonUtil<Object> addOrUpProject(@RequestParam(value = "files",required = false) MultipartFile multipartFile,
                                                 @RequestParam("projectName") String projectName,
                                                 @RequestParam("visitPath") String visitPath,
                                                 @RequestParam("remark") String remark,
                                                 @RequestParam("id") Integer id,
                                                 @RequestParam("httpPath") String httpPath,
                                                 @RequestParam("isZpk") Integer isZpk,
                                                 @RequestParam("isMp4") Integer isMp4,
                                                 @RequestParam("type") String type,
                                                 Authentication authentication) throws IOException {
        if(id <= 0){
            id = null;
        }
        if(isZpk.equals(0)){
            if(StringUtils.isEmpty(visitPath)){
                return new ResultJsonUtil().fail("访问路径不能为空");
            }
            QueryWrapper<SysProject> map = new QueryWrapper();
            map.eq("visit_path",visitPath);
            SysProject sysProjectIsPath = sysProjectService.getOne(map);

            //整体路径（云配置路径） + 访问路径
            String uploadPath = nacosConfig.getProjectPath() + visitPath;
            File tempFile = new File(uploadPath);
            //旧的文件访问地址
            String oldvisitPath ="";
            //是否是修改数据
            if(id != null){
                //判断唯一访问后缀
                if(sysProjectIsPath != null && !sysProjectIsPath.getId().equals(id)){
                    return new ResultJsonUtil().fail("访问后缀已存在");
                }
                SysProject sysProject = sysProjectService.getById(id);
                if(sysProject != null){
                    //原地址
                    oldvisitPath = sysProject.getVisitPath();
                }else {
                    return new ResultJsonUtil().fail("不存在的ID");
                }
            }else {
                //判断唯一访问后缀
                if(sysProjectIsPath != null){
                    return new ResultJsonUtil().fail("访问后缀已存在");
                }
            }
            if(id != null){
                if(StringUtils.isNotEmpty(oldvisitPath) && !oldvisitPath.equals(visitPath)){
                    //修改原文件名称
                    File file=new File(nacosConfig.getProjectPath() + oldvisitPath); //指定文件名及路径
                    file.renameTo(tempFile);
                }
            }
        }
        Claims claims = JwtUtil.getJwtInfo(authentication);
        String userName = (String) claims.get("user_name");
        SysProject sysProject = new SysProject();
        sysProject.setId(id);
        sysProject.setHttpPath(nacosConfig.getProjecrUrl()+visitPath);
        sysProject.setUserName(userName);
        sysProject.setRemark(remark);
        sysProject.setProjectName(projectName);
        sysProject.setUpdateTime(new Date());
        sysProject.setVisitPath(visitPath);
        sysProject.setHttpPath(httpPath);
        sysProject.setIsMp4(isMp4);
        sysProject.setType(type);
        sysProject.setIsZpk(isZpk);
        sysProjectService.saveOrUpdate(sysProject);
        return new ResultJsonUtil().success("部署成功");
    }

    @GetMapping("/zipUncompress/{visitPath}")
    public ResultJsonUtil<Object> zipUncompress(@PathVariable("visitPath") String visitPath, HttpServletResponse response) {
        try {
            //解压
            multipartFileToFile.ZipUncompress(nacosConfig.getProjectPath()+visitPath+".zip",nacosConfig.getProjectPath()+visitPath);
            //强制关闭资源 避免删除文件时被占用
            System.gc();
            //等待2秒后删除文件
            Thread.sleep(2000);
            //删除ZIP文件
            multipartFileToFile.DeleteFolder(nacosConfig.getProjectPath()+visitPath+".zip");

            //修改 最后更新时间和访问路径
            SysProject sysProject = new SysProject();
            sysProject.setUpdateTime(new Date());
            sysProject.setHttpPath(nacosConfig.getProjecrUrl()+visitPath);
            sysProjectService.update(sysProject, new QueryWrapper<SysProject>().eq("visit_path", visitPath));

        } catch (Exception e) {
            e.printStackTrace();
            return new ResultJsonUtil().customFail("解压失败，请上传UTF-8编码的zip文件");
        }
        return new ResultJsonUtil().success("解压成功");
    }



    /**
     * 文件块上传
     *
     * @param chunk
     * @return
     */
    @AnonymousAccess
    @PostMapping("/fileUpload")
    public String fileUpload(@ModelAttribute Chunk chunk, HttpServletResponse response){
        if(!chunk.getFilename().substring(chunk.getFilename().indexOf("."),chunk.getFilename().length()).equals(".zip")){
            response.setStatus(500);
            return "exception:notZip";
        }
        File file= new File(nacosConfig.getProjectPath(), chunk.getVisitPath()+".zip");
        //第一个块,则新建文件
        if(chunk.getChunkNumber()==1 && !file.exists()){
            try {
                file.createNewFile();
            } catch (IOException e) {
                response.setStatus(500);
                return "exception:createFileException";
            }
        }
        //进行写文件操作
        try(
                //将块文件写入文件中
                InputStream fos=chunk.getFile().getInputStream();
                RandomAccessFile raf =new RandomAccessFile(file,"rw")
        ) {
            int len=-1;
            byte[] buffer=new byte[1024];
            raf.seek((chunk.getChunkNumber()-1)*1024*1024*5);
            while((len=fos.read(buffer))!=-1){
                raf.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
            if(chunk.getChunkNumber()==1) {
                file.delete();
            }
            response.setStatus(507);
            return "exception:writeFileException";
        }
        if(chunk.getChunkNumber().equals(chunk.getTotalChunks())){
            response.setStatus(200);
            // TODO 向数据库中保存上传信息
            return "over";
        }else {
            response.setStatus(201);
            return "ok";
        }
    }

    @ApiOperation(value = "app端关注项目接口")
    @GetMapping("/followProject/{id}")
    public ResultJsonUtil<Object> followProject(@PathVariable("id") Integer id,
                                                  Authentication authentication) {
        //获取当前登录用户基本权限信息
        UserJurisdiction userJurisdiction = JwtUtil.getUserJurisdiction(authentication);
        String key = userFollowPro+userJurisdiction.getUserId();
        //获取关注长度，按关注顺序添加
        Long count = redisTemplate.opsForZSet().size(key);
        if(count == null){
            count = 0L;
        }
        //将关注的项目id存入redis
        redisTemplate.opsForZSet().add(userFollowPro+userJurisdiction.getUserId(),id,count++);
        //项目关注用户列表
        redisTemplate.opsForSet().add(proFollow+id,userJurisdiction.getUserId());
        return new ResultJsonUtil().success("关注成功");
    }

    @ApiOperation(value = "app端取消关注项目接口")
    @GetMapping("/cancelfollowProject/{id}")
    public ResultJsonUtil<Object> cancelfollowProject(@PathVariable("id") Integer id,
                                                Authentication authentication) {
        //获取当前登录用户基本权限信息
        UserJurisdiction userJurisdiction = JwtUtil.getUserJurisdiction(authentication);
        //删除redis中关注的元素
        redisTemplate.opsForZSet().remove(userFollowPro+userJurisdiction.getUserId(),id);

        //删除项目关注用户
        redisTemplate.opsForSet().remove(proFollow+id,userJurisdiction.getUserId());

        return new ResultJsonUtil().success("取关成功");
    }

    @ApiOperation(value = "获取当前关注数量")
    @GetMapping("/getGzCount")
    public ResultJsonUtil<Object> getGzCount(Authentication authentication, HttpServletResponse response) {
        //获取当前登录用户基本权限信息
        UserJurisdiction userJurisdiction = JwtUtil.getUserJurisdiction(authentication);
        String key =  userFollowPro+userJurisdiction.getUserId();
        //获取关注长度，按关注顺序添加
        Long count = redisTemplate.opsForZSet().size(key);
        return new ResultJsonUtil().success(count);
    }

    @ApiOperation(value = "获取获奖作品数量")
    @GetMapping("/getAwardCount")
    public ResultJsonUtil<Object> getAwardCount() {
        //获取当前登录用户基本权限信息
        QueryWrapper<SysProject> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("type","5");
        return new ResultJsonUtil().success(sysProjectService.list(queryWrapper).size());
    }
}